/*
 * auxiliary.c
 *
 *  Created on: Mar 12, 2012
 *      Author: qian
 */

/*
 * auxiliary.c
 *
 *  Created on: May 17, 2011
 *      Author: qian
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "auxiliary.h"

/*print out usage when cmd input not right*/
void usage(int argc, char **argv)
{
	fprintf(stdout, "Usage: %s -lcf <file> [-o <file>] [-t_map <file>]\n", argv[0]);
	fprintf(stdout, "A thermal simulator that reads power trace from a file and outputs temperatures.\n");
	fprintf(stdout, "Options:(may be specified in any order, within \"[]\" means optional)\n");
	fprintf(stdout, "   -lcf <file>\tlayer configuration file that contains essential info about 3D stack\n");
	fprintf(stdout, "  [-o <file>]\ttext file to record the steady state temperature of floorplan units\n");
	fprintf(stdout, "  [-t_map <file>]\tgrid level temperature detail to generate the thermal map\n");
}

/*error handler*/
void fatal(char *s)
{
	fprintf(stderr, "error: %s", s);
	exit(1);
}

/*
 * the command line is of the form <prog_name> <name-value pairs> where
 * <name-value pairs> is of the form -<variable> <value>
 */

int parse_cmdline(str_pair *table, int argc, char **argv)
{
	int i, count;
	for (i=1, count=0; i < argc; i++) {
		if (i % 2) {	/* variable name	*/
			if (argv[i][0] != '-')
				fatal("invalid command line. check usage\n");
			/* ignore the leading "-"	*/
			strncpy(table[count].name, &argv[i][1], STR_SIZE-1);
			table[count].name[STR_SIZE-1] = '\0';
		} else {		/* value	*/
			strncpy(table[count].value, argv[i], STR_SIZE-1);
			table[count].value[STR_SIZE-1] = '\0';
			count++;
		}
	}
	return count;
}

/* table lookup	for a name */
int get_str_index(str_pair *table, int size, char *str)
{
	int i;

	if (!table)
		fatal("null pointer in get_str_index\n");

	for (i = 0; i < size; i++)
		if (!strcasecmp(str, table[i].name))
			return i;
	return -1;
}

/*fill up the input output options*/
void fill_IO_opt(IO_t *IO_opt, str_pair *table, int size)
{
	int idx;

	if ((idx = get_str_index(table, size, "lcf")) >= 0) {
		if(sscanf(table[idx].value, "%s", IO_opt->lcf) != 1)
			fatal("invalid format for layer configuration file\n");
	} else {
		fatal("required parameter layer configuration file missing. check usage\n");
	}

	if ((idx = get_str_index(table, size, "o")) >= 0) {
		if(sscanf(table[idx].value, "%s", IO_opt->steady_temp) != 1)
			fatal("invalid format for block output file\n");
	}
	if ((idx = get_str_index(table, size, "t_map")) >= 0) {
		if(sscanf(table[idx].value, "%s", IO_opt->thermal_map) != 1)
			fatal("invalid format for thermal_map file\n");
	}
}

/*
 * reads tab-separated name-value pairs from file into
 * a table of size max_entries and returns the number
 * of entries read successfully
 */
int read_str_pairs(str_pair *table, int max_entries, char *file)
{
	int i=0;
	char str[LINE_SIZE], copy[LINE_SIZE];
	char name[STR_SIZE];
	char *ptr;
	FILE *fp = fopen (file, "r");
	if (!fp) {
		sprintf (str,"error: %s could not be opened for reading\n", file);
		fatal(str);
	}
	while(i < max_entries) {
		fgets(str, LINE_SIZE, fp);
		if (feof(fp))
			break;
		strcpy(copy, str);

		/* ignore comments and empty lines  */
		ptr = strtok(str, " \r\t\n");
		if (!ptr || ptr[0] == '#')
			continue;

		if ((sscanf(copy, "%s%s", name, table[i].value) != 2) || (name[0] != '-'))
			fatal("invalid file format\n");
		/* ignore the leading "-"	*/
		strcpy(table[i].name, &name[1]);
		i++;
	}
	fclose(fp);
	return i;
}


/*
 * find the number of non-empty, non-comment lines
 * in a file open for reading
 */
int count_significant_lines(FILE *fp)
{
    char str[LINE_SIZE], *ptr;
    int count = 0;

	fseek(fp, 0, SEEK_SET);
	while(!feof(fp)) {
		fgets(str, LINE_SIZE, fp);
		if (feof(fp))
			break;

		/* ignore comments and empty lines	*/
		ptr = strtok(str, " \r\t\n");
		if (!ptr || ptr[0] == '#')
			continue;

		count++;
	}
	return count;
}

/*compare two numbers if equal return 1*/
int eq(double x, double y)
{
	return (fabs(x-y) <  DELTA);
}


int tolerant_ceil(double val)
{
	double nearest = floor(val+0.5);
	/* numbers close to integers	*/
	if (eq(val, nearest))
		return ((int) nearest);
	/* all others	*/
	else
		return ((int) ceil(val));
}

int tolerant_floor(double val)
{
	double nearest = floor(val+0.5);
	/* numbers close to integers	*/
	if (eq(val, nearest))
		return ((int) nearest);
	/* all others	*/
	else
		return ((int) floor(val));
}


int double2int(double value)
{
	int d;

	char buffer[12];
	d = atoi(gcvt(value, 10, buffer));

	return d;
}

void dump_sparse_matrix(int *Ap, int *Ai, double *Ax, int size, char *file)
{
    int i,j, k, flag;
	FILE *matrixdetail=fopen(file, "wb");
    fprintf(matrixdetail, "Ap:\n");
    for(i=0;i<size;i++)
    	fprintf(matrixdetail, "%d\t", Ap[i]);
    fprintf(matrixdetail, "%d\n", Ap[size]);

    fprintf(matrixdetail, "Ai:\n");
    for(i=0;i<Ap[size]-1;i++)
    	fprintf(matrixdetail, "%d\t", Ai[i]);
    fprintf(matrixdetail, "%d\n", Ai[Ap[size]-1]);

    fprintf(matrixdetail, "Ax:\n");
    for(i=0;i<Ap[size]-1;i++)
    	fprintf(matrixdetail, "%f\t", Ax[i]);
    fprintf(matrixdetail, "%f\n", Ax[Ap[size]-1]);

    fprintf(matrixdetail, "Ax_matrix:\n");
    for(i=0;i<size;i++)
    {
    	for(j=0;j<size;j++)
    	{
    		flag=0;
    		for(k=Ap[j];k<Ap[j+1];k++)
    			if(Ai[k]==i)
    			{
    				fprintf(matrixdetail, "%f\t", Ax[k]);
    				flag=1;
    			}
    		if(flag==0)
    			fprintf(matrixdetail, "%d\t", 0);

    	}
    	fprintf(matrixdetail, "\n");
    }


    fclose(matrixdetail);
}

/* get resistor value by conductivity, area and length
 * R = L / (k * A)
 */
double getr(double k, double l, double area) {
	return l / (k * area);
}
